#pragma once

#include "..\\headers.default.h"

#include "NodeInstance.h"
#include "AbstractTree.h"
#include "TreeInstance.h"

using namespace loirey;

namespace and_or_tree
{
	class CFileNameList
	{
	public:
		int FileAmount;
		CSimpleTypeArray<string> TitleList;
		CSimpleTypeArray<string> FullFileNameList;

	public:
		void myInit(string strPN_Base, string strFN_Suffix, int FileIndexStart, int FileIndexWidth, int FileAmount);
		void myInit(string strFN_FileNameList);
	public:
		string Title(int FileIndex) const;
		string FullFileName(int FileIndex) const;
	};

	class CPerceptronModel
	{
	public:
		static double S_InstanceMaxScale;
		static double S_InstanceMaxRotation;
		static double S_BrothersMaxScaleDifference;
		static double S_BrothersMaxRotationDifference;
		static int S_MaxChoiceCandidateAmount;
		static int S_AppearanceFeatureBinAmount;
		static double S_DefaultTargetRecall;
		static int S_ChoiceLowLimit;
		static int S_ChoiceHighLimit;
		static int S_TrainRoundAmount;
		static int S_PerNegImageInstanceAmountForTrain;
		static int S_TestPrintAmountPerImageForTest;
		static double S_MAXIMUM_SCORE;
		static double S_IMAGE_BOUNDARY;
	public:
		const CAbstractTree* pTree;
	public:
		int CoefficientAmount_Shape;
		CSimpleTypeArray<int> CoefficientOffsetList_Shape;
		CSimpleTypeArray<double> CoefficientList_Shape;
		int CoefficientAmount_Appearance;
		CSimpleTypeArray<int> CoefficientOffsetList_Appearance;
		CSimpleTypeArray<double> CoefficientList_Appearance;
		double ScoreScaler;
	public:
		CSimpleTypeArray<CRichInstance> StandardNodeInstanceList;
		CSimpleTypeArray<double> StandardLeafNodeOrientationList;

		int FeatureDimension_Shape;
		CSimpleTypeArray<int> FeatureOffsetList_Shape;
		CSimpleTypeArray<double> FeatureMeanList_Shape;
		CSimpleTypeArray<double> FeatureVarianceList_Shape;

		int FeatureDimension_Appearance;
		CSimpleTypeArray<int> FeatureOffsetList_Appearance;
		CSimpleTypeArray<CHistogramConfig> FeatureHistogramConfigList_Appearance;
		CSimpleTypeArray<CSimpleTypeArray<double>> FeatureBinValueList_Appearance;
	public:
		CSimpleTypeArray<double> NodeParsingScoreThresholdList;
	protected:
		CSimpleTypeArray<double> _TempShapeFeatureList;
		CSimpleTypeArray<double> _TempAppearanceFeatureList;

	public:
		static void InitDefaultParameters();
	public:
		bool LoadFromFile(string strFN_Model);
		bool InputFromStream(istream& inStream);
		void SaveToFile(string strFN_Model) const;
		void OutputToStream(ostream& outStream) const;
		void TranslateFromYuanhaoModel(string strFN_YuanhaoModel);
	public:
		void ConvertShapeFeature(CSimpleTypeArray<double>& DstShapeFeatureList, int NodeIndex) const;
		void ConvertAppearanceFeature(CSimpleTypeArray<double>& DstAppearanceFeatureList, int NodeIndex) const;
		void ConvertTreeFeature_SingleInstance(
			CSimpleTypeArray<double>& DstConvertedShapeFeatureList,
			CSimpleTypeArray<double>& DstConvertedAppearanceFeatureList,
			const CSimpleTypeArray<double>& SrcOriginalShapeFeatureList,
			const CSimpleTypeArray<double>& SrcOriginalAppearanceFeatureList
			);
	protected:
		static double ComputePerceptronScore(
			int CoefficientOffset,
			const CSimpleTypeArray<double>& CoefficientList,
			const double* FeatureList,
			int Dimension
			);
		double ComputeShapeScore(int NodeIndex, const CSimpleTypeArray<double>& SrcConvertedShapeFeatureList, size_t Offset = 0) const;
		double ComputeAppearanceScore(int NodeIndex, const CSimpleTypeArray<double>& SrcConvertedAppearanceFeatureList, size_t Offset = 0) const;
	public:
		void ComputeNodeConvertedShapeFeature(
			CSimpleTypeArray<double>& DstConvertedShapeFeatureList,
			const CTreeInstance& TreeInstance, int NodeIndex,
			const CParsedInstance* pParsedInstance
			) const;
		void ComputeNodeConvertedShapeFeature(
			CSimpleTypeArray<double>& DstConvertedShapeFeatureList,
			const CTreeInstance& TreeInstance, int NodeIndex,
			const CInstanceChoice* pInstanceChoice
			) const;
		void ComputeNodeConvertedAppearanceFeature(
			CSimpleTypeArray<double>& DstConvertedAppearanceFeatureList,
			const CTreeInstance& TreeInstance, int NodeIndex,
			const CParsedInstance* pParsedInstance
			) const;
		void ComputeNodeConvertedAppearanceFeature(
			CSimpleTypeArray<double>& DstConvertedAppearanceFeatureList,
			const CTreeInstance& TreeInstance, int NodeIndex,
			const CInstanceChoice* pInstanceChoice
			) const;
		void ComputeNodeConvertedFullFeature(
			CSimpleTypeArray<double>& DstConvertedShapeFeatureList,
			CSimpleTypeArray<double>& DstConvertedAppearanceFeatureList,
			const CTreeInstance& TreeInstance, int NodeIndex,
			const CParsedInstance* pParsedInstance
			) const;
		void ComputeNodeConvertedFullFeature(
			CSimpleTypeArray<double>& DstConvertedShapeFeatureList,
			CSimpleTypeArray<double>& DstConvertedAppearanceFeatureList,
			const CTreeInstance& TreeInstance, int NodeIndex,
			const CInstanceChoice* pInstanceChoice
			) const;
	public:
		void ComputeNodeShapeScore(
			CParsedInstance* pDstParsedInstance,
			const CTreeInstance& TreeInstance, int NodeIndex,
			const CSimpleTypeArray<double>& SrcConvertedShapeFeatureList
			) const;
		void ComputeNodeShapeScore(
			CInstanceChoice* pDstInstanceChoice,
			const CTreeInstance& TreeInstance, int NodeIndex,
			const CSimpleTypeArray<double>& SrcConvertedShapeFeatureList
			) const;
		void ComputeNodeAppearanceScore(
			CParsedInstance* pDstParsedInstance,
			const CTreeInstance& TreeInstance, int NodeIndex,
			const CSimpleTypeArray<double>& SrcConvertedAppearanceFeatureList
			) const;
		void ComputeNodeAppearanceScore(
			CInstanceChoice* pDstInstanceChoice,
			const CTreeInstance& TreeInstance, int NodeIndex,
			const CSimpleTypeArray<double>& SrcConvertedAppearanceFeatureList
			) const;
		void ComputeNodeTotalScore(
			CParsedInstance* pDstParsedInstance,
			const CTreeInstance& TreeInstance, int NodeIndex,
			const CSimpleTypeArray<double>& SrcConvertedShapeFeatureList,
			const CSimpleTypeArray<double>& SrcConvertedAppearanceFeatureList
			) const;
		void ComputeNodeTotalScore(
			CInstanceChoice* pDstInstanceChoice,
			const CTreeInstance& TreeInstance, int NodeIndex,
			const CSimpleTypeArray<double>& SrcConvertedShapeFeatureList,
			const CSimpleTypeArray<double>& SrcConvertedAppearanceFeatureList
			) const;
	public:
		void ComputeTreeParsedInstanceTotalScore(CTreeInstance& TreeInstance) const;
		void ComputeTreeInstanceChoiceTotalScore(CTreeInstance& TreeInstance) const;
		void ComputeTreeTotalScore_ByFeature(
			CTreeInstance& TreeInstance,
			const CSimpleTypeArray<double>& SrcConvertedShapeFeatureList,
			const CSimpleTypeArray<double>& SrcConvertedAppearanceFeatureList
			) const;
		void ComputeTreeTotalScore_ByFeature(
			CSimpleTypeArray<double>& DstTreeTotalScoreList,
			const CSimpleTypeArray<double>& SrcConvertedShapeFeatureList,
			const CSimpleTypeArray<double>& SrcConvertedAppearanceFeatureList
			) const;
		void ComputeTreeTotalScore_ByFeature(
			CSimpleTypeArray<double>& DstNodeShapeScoreList,
			CSimpleTypeArray<double>& DstNodeAppearanceScoreList,
			CSimpleTypeArray<double>& DstNodeTotalScoreList,
			CSimpleTypeArray<double>& DstTreeShapeScoreList,
			CSimpleTypeArray<double>& DstTreeAppearanceScoreList,
			CSimpleTypeArray<double>& DstTreeTotalScoreList,
			const CSimpleTypeArray<double>& SrcConvertedShapeFeatureList,
			const CSimpleTypeArray<double>& SrcConvertedAppearanceFeatureList
			) const;
	protected:
		static void MakePosShapeFeatureFileName(char* DstFileName, const char* strPN_Training, int PosFileIndex);
		static void MakePosAppearanceFeatureFileName(char* DstFileName, const char* strPN_Training, int PosFileIndex);
	protected:
		bool _ExtractInternalNodeParsedInstance(
			CParsedInstance* pDstParsedInstance,
			const CTreeInstance& TreeInstance, int NodeIndex,
			const CSimpleTypeArray<const CParsedInstance*>& ChildrenPiptrList,
			const CSimpleTypeArray<bool>& AreChildrenFakeList) const;
	public:
		bool ExtractInternalNodeParsedInstance(CTreeInstance& TreeInstance, int NodeIndex) const;
		bool ExtractInternalNodeInstanceChoice(
			CInstanceChoice* pDstInstanceChoice,
			const CTreeInstance& TreeInstance, int NodeIndex,
			const CSimpleTypeArray<int> ChildrenChoiceIndexList) const;
	public:
		void ExtractLeafNodeParsedInstance(CParsedInstance* pDstParsedInstance, const CTreeInstance& TreeInstance, int NodeIndex, int xy) const;
		void ExtractLeafNodeInstanceChoice(CInstanceChoice* pDstIntanceChoice, const CTreeInstance& TreeInstance, int NodeIndex, int xy) const;
		void ExtractLeafNodeParsedInstance(CParsedInstance* pDstParsedInstance, const CTreeInstance& TreeInstance, int NodeIndex, double x, double y) const;
		void ExtractLeafNodeInstanceChoice(CInstanceChoice* pDstIntanceChoice, const CTreeInstance& TreeInstance, int NodeIndex, double x, double y) const;
	protected:
		void _GenerateChildrenChoiceList(
			CSimpleTypeArray<CInstanceChoice>& DstInstanceChoiceList,
			CSimpleTypeArray<int> ChildrenChoiceIndexList,
			CTreeInstance& TreeInstance, int NodeIndex, int MaxCandidateAmount,
			int ChildrenAmount, const int* pChildrenNodeIndex, const CRichInstance& StdRichInstance,
			int CurrentDepth) const;
		void _GenerateInternalNodeInstanceCandidateList(CTreeInstance& TreeInstance, int NodeIndex, int MaxCandidateAmount) const;
	protected:
		bool _FillMissingTreeAndComputeScore(
			CInstanceChoice* pDstInstanceChoice,
			CTreeInstance& TreeInstance, int NodeIndex,
			bool fComputeScore, bool fReserveFakeInstance
			) const;
	public:
		int ParseInternalNode(CTreeInstance& TreeInstance, int NodeIndex, int ChoiceLowLimit, int ChoiceHighLimit, bool fUseScoreThreshold) const;
		void ParseAllLeafNodes(CTreeInstance& TreeInstance, int ChoiceLowLimit, int ChoiceHighLimit, bool fUseScoreThreshold) const;
		void ParseTree(const CImg<int> imgSrcRGB, CTreeInstance& TreeInstance, bool fUseScoreThreshold) const;
		void ParseTree(string strFN_Image, CTreeInstance& TreeInstance, bool fUseScoreThreshold) const;
		void ParseTree(CTreeInstance& TreeInstance, bool fUseScoreThreshold) const;
		void ParseGroundTruth(string strFN_GroundTruth, CTreeInstance& TreeInstance) const;
	protected:
		void _BuildStandardNodeInstanceList();
	public:
		void InitTree(const CAbstractTree* pFixedAndOrTree);
		void InitStandardModel(const CFileNameList& TrainPosFileList);
		void PrecomputePosFileOriginalFeature(
			const CFileNameList& TrainPosFileList,
			string strPN_TrainPosFeature
			);
		void InitConvertingFunctions(const CFileNameList& TrainPosFileList, const CFileNameList& TrainNegFileList);
	public:
		void UpdateModel(CSimpleTypeArray<double>& DeltaCoefficientList, double Alpha = 1.0);
		void NormalizeModel(bool fNormalizeScoreScaler);
		void ComputeNodeScoreThresholdForParsing(const CFileNameList& TrainPosFileList, double TargetRecall);
		void ComputeNodeScoreThresholdForParsing(int TrainPosFileAmount, string strPN_TrainPosFeature, double TargetRecall);
	public:
		void Train(
			const CFileNameList& TrainPosFileList, const CFileNameList& TrainNegFileList,
			string strPN_TrainPosFeature, string strPN_ParsedImage, string strPN_NewModel,
			ostream& oLog
			);
		void Test(
			const CFileNameList& FileList, bool fTypePosNeg,
			string strPN_TrainPosFeature, string strPN_ParsedImage,
			ostream& oLog
			);
	protected:
		void _UpdateModel(
			double* pDeltaCoefficient_Shape, double* pDeltaCoefficient_Appearance,
			const CSimpleTypeArray<double>& PrecomputedShapeFeatureList,
			const CSimpleTypeArray<double>& PrecomputedAppearanceFeatureList,
			int NodeIndex, double Alpha);
		void _UpdateModel(
			double* pDeltaCoefficient_Shape, double* pDeltaCoefficient_Appearance,
			const CTreeInstance& TreeInstance, int NodeIndex, double Alpha);
	};
}

